"""
__author__ = 'loong'
"""
from baye.structures import read_struct, sizeof, decode_data, write_struct
from baye import models
from baye import resid
from baye.util import chunk
from xml.etree import cElementTree as ET
import codecs


class Res:
    def __init__(self, id):
        self.id = id
        self.comment = ''
        self.items = []
        self.raw = b''

    @classmethod
    def parse_bin(cls, id, data):
        res = cls(id)
        res.parse_items(data)
        return res

    def parse_items(self, data):
        head = read_struct(data, 0, models.RESHEAD)
        headLen = sizeof(models.RESHEAD)
        self.raw = data[headLen: head['resLen']]
        for i in range(head['itemCnt']):
            self.items.append(self.parse_item(head, data, i))

    def parse_item(self, head, dat, idx):
        headLen = sizeof(models.RESHEAD)
        if head['itemLen']:
            length = head['itemLen']
            offset = idx * length + headLen
        elif not self.raw:
            return b''
        elif head['itemCnt'] == 1:
            length = head['resLen'] - headLen
            offset = headLen
        else:
            iaddr = idx * sizeof(models.RIDX) + headLen
            rIdx = read_struct(dat, iaddr, models.RIDX)
            length = rIdx['rlen']
            offset = rIdx['offset']
        data = dat[offset: offset+length]
        key = head['resKey']
        if key:
            data = decode_data(data, key)
        return data

    @property
    def count(self):
        return len(self.items)

    def xml(self):
        node = ET.Element("res")
        node.attrib['id'] = '%02X' % self.index
        node.attrib['doc'] = str(self.comment)
        for i in range(self.count):
            ch = ET.Element('i')
            doc = '%02X' % (i + 1)
            cmt = resid.get_comment(self.index, i)
            if cmt:
                doc += ' ' + cmt
            ch.attrib['doc'] = doc
            hex = codecs.encode(self.items[i], 'hex_codec').decode('utf8').upper()
            ch.text = '\n'.join(chunk(hex, 80))
            node.append(ch)
        if self.count == 0:
            hex = codecs.encode(self.raw, 'hex_codec').decode('utf8').upper()
            node.text = '\n'.join(chunk(hex, 80))
        return node

    @classmethod
    def from_xml(cls, xml):
        res = cls(int(xml.attrib['id'], 16))

        for i in xml:
            hexdata = (i.text or '')
            hexdata = ''.join(hexdata.split())
            dat = codecs.decode(hexdata, 'hex_codec')
            res.items.append(dat)

        if xml.text.strip():
            hexdata = ''.join(xml.text.split())
            dat = codecs.decode(hexdata, 'hex_codec')
            res.raw = dat

        return res

    def bin(self):
        itemLen = 0
        itemCnt = self.count
        resID = self.id
        resKey = 0
        reserved = 0

        if self.count == 0:
            resLen = sizeof(models.RESHEAD) + len(self.raw)
            payload = self.raw
        else:
            lens = set()
            il = 0
            payload = b''

            for item in self.items:
                il = len(item)
                lens.add(il)

            if len(lens) > 1 or il == 0:
                # 变长
                idxes = b''
                ipayload = b''
                idxLen = sizeof(models.RIDX) * itemCnt

                offset = sizeof(models.RESHEAD) + idxLen

                for i in self.items:
                    rlen = len(i)
                    idx = write_struct({'offset': offset, 'rlen': rlen}, models.RIDX)
                    idxes += idx
                    ipayload += i
                    offset += rlen
                payload += idxes + ipayload
                resLen = offset
            else:
                itemLen = il
                resLen = sizeof(models.RESHEAD) + itemLen*itemCnt
                for i in self.items:
                    payload += i

        head = write_struct({'resLen': resLen,
                             'resID': resID,
                             'itemCnt': itemCnt,
                             'itemLen': itemLen,
                             'resKey': resKey,
                             'reserved': reserved},
                            models.RESHEAD)
        return head + payload

if __name__ == "__main__":
    res = Res(1)
    res.items = [b'123', b'4567']
    bin = res.bin()
    print(bin)
    res = Res.parse_bin(1, bin)
    print(res.items)
